package com.gopay.bis.spdb.appay.operation;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.alibaba.fastjson.serializer.SerializeWriter;
import com.gopay.bis.spdb.appay.impl.ApaySpdbBankServiceImpl;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.spdb.agpay.MicroPayBody;
import com.gopay.common.domain.bank.spdb.agpay.PayNotify;
import com.gopay.common.domain.bank.spdb.agpay.QueryOrderBody;
import com.gopay.common.domain.bank.spdb.agpay.RefundBody;
import com.gopay.common.domain.bank.spdb.agpay.ReverseBody;
import com.gopay.common.domain.bank.spdb.agpay.ScanPayBody;
import com.gopay.common.domain.bank.spdb.agpay.SdkPayBody;
import com.gopay.common.exception.GopayException;
import com.gopay.remote.bank.ICertHelperThirdParty;

public class ApaySpdbCerHelper implements ICertHelperThirdParty {
	private static Logger logger = LoggerFactory.getLogger(ApaySpdbCerHelper.class);
	/**
	 * SHA256摘要算法
	 */
	public static final String SHA256="SHA-256";

	@Override
	public String sign(Object requestMsg) throws GopayException {
		// TODO Auto-generated method stub
		try {
			Class c = null;
			if(requestMsg instanceof SdkPayBody){
				c = SdkPayBody.class;
			}else if(requestMsg instanceof ScanPayBody){
				c = ScanPayBody.class;
			}else if(requestMsg instanceof QueryOrderBody){
				c = QueryOrderBody.class;
			}else if(requestMsg instanceof MicroPayBody){
				c = MicroPayBody.class;
			}else if(requestMsg instanceof RefundBody){
				c = RefundBody.class;
			}else if(requestMsg instanceof ReverseBody){
				c = ReverseBody.class;
			}else{
				throw new GopayException(ProcCodeConstants.PROC_CODE_100E6029, "spdb agpay 不支持的签名类型");
			}
			return getSign(requestMsg, c);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6029, e.getMessage());
		}
	}

	@Override
	public Object verify(Object responseMsg) throws GopayException {
		// TODO Auto-generated method stub
		try {
			if(responseMsg instanceof SdkPayBody){
				SdkPayBody response = (SdkPayBody)responseMsg;
				response.setTransTime(response.getTransTime().replaceAll("\\+", " "));
				String sign = getSign(response, SdkPayBody.class);
				String oriSign = response.getSign();
				return oriSign.equals(sign);
			}else if(responseMsg instanceof ScanPayBody){
				ScanPayBody response = (ScanPayBody)responseMsg;
				response.setTransTime(response.getTransTime().replaceAll("\\+", " "));
				String sign = getSign(response, ScanPayBody.class);
				String oriSign = response.getSign();
				return oriSign.equals(sign);
			}else if(responseMsg instanceof QueryOrderBody){
				QueryOrderBody response = (QueryOrderBody)responseMsg;
				response.setTransTime(response.getTransTime().replaceAll("\\+", " "));
				String sign = getSign(response, QueryOrderBody.class);
				String oriSign = response.getSign();
				return oriSign.equals(sign);
			}else if(responseMsg instanceof MicroPayBody){
				MicroPayBody response = (MicroPayBody)responseMsg;
				response.setTransTime(response.getTransTime().replaceAll("\\+", " "));
				String sign = getSign(response, MicroPayBody.class);
				String oriSign = response.getSign();
				return oriSign.equals(sign);
			}else if(responseMsg instanceof RefundBody){
				RefundBody response = (RefundBody)responseMsg;
				response.setTransTime(response.getTransTime().replaceAll("\\+", " "));
				String sign = getSign(response, RefundBody.class);
				String oriSign = response.getSign();
				return oriSign.equals(sign);
			}else if(responseMsg instanceof ReverseBody){
				ReverseBody response = (ReverseBody)responseMsg;
				response.setTransTime(response.getTransTime().replaceAll("\\+", " "));
				String sign = getSign(response, ReverseBody.class);
				String oriSign = response.getSign();
				return oriSign.equals(sign);
			}else if(responseMsg instanceof PayNotify){
				PayNotify response = (PayNotify)responseMsg;
				//response.setTransTime(response.getTransTime().replaceAll("\\+", " "));
				response.setTransTime(response.getTransTime().replaceAll( " ", "\\+"));
				response.setCharset("utf-8");
				response.setVersion("2.2");
				String sign = getSign(response, PayNotify.class);
				String oriSign = response.getPlainMessage();				
				return oriSign.equals(sign);
			}else{
				throw new GopayException(ProcCodeConstants.PROC_CODE_100E6029, "spdb agpay 不支持的验签类型");
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6029, e.getMessage());
		}
	}
	
	public <T> T fromJson(String json, Class<T> clazz){
//		T t = JSON.parseObject(json,new TypeReference<T>(){});
		T t = JSON.parseObject(json,clazz);
		return t;
	}
	
	public String getJson(Object obj, Class<?> clazz){
        Field[] fields = clazz.getDeclaredFields();
        final Set<String> fieldNames = new HashSet<String>();
        for(Field field : fields){
        	Class fieldClazz = field.getType();
        	if(!isJavaClass(fieldClazz)||fieldClazz==List.class){
        		Field[] customTypeParamFields = null;
        		//是否是List，如果是List，取泛型类型
        		if (fieldClazz.isAssignableFrom(List.class)) {
        			Type fc = field.getGenericType();
        			if(fc == null) continue;
        			if(fc instanceof ParameterizedType) {
        				ParameterizedType pt = (ParameterizedType) fc;  
        				Class genericClazz = (Class)pt.getActualTypeArguments()[0];
        				customTypeParamFields = genericClazz.getDeclaredFields();
        			}
        		}else{
        			customTypeParamFields = field.getType().getDeclaredFields();
        		}
        		for (Field field2 : customTypeParamFields) {
        			fieldNames.add(field2.getName());
				}
        	}
        	fieldNames.add(field.getName());
        }
        PropertyFilter filter = new PropertyFilter() {
            // name：属性名称，value：属性值
            public boolean apply(Object source, String name, Object value) {
                // 当属性是属于指定子类时
                if (fieldNames.contains(name)&&!"signKey".equals(name)) {
                    // true 需要序列化，过滤出来
                    return true;
                }
                // false 无需序列化，不过滤出来
                return false;
            }
        };

        SerializeWriter out = new SerializeWriter();
        JSONSerializer serializer = new JSONSerializer(out);
        serializer.getPropertyFilters().add(filter);

        serializer.write(obj);

        String text = out.toString();
        return text;
    }
	
	/**
	 * 是否是自定义类型
	 * @param clz
	 * @return
	 */
	private boolean isJavaClass(Class<?> clz) {    
	    return (clz != null && clz.getClassLoader() == null) || clz==String.class ;    
	}
	
	private String getSign(Object msg,Class<?> clazz) throws Exception{
		Map<String,String> signMap = new HashMap<String, String>();
		Field[] fields = clazz.getDeclaredFields();
		String signKey = "";
		for (Field field : fields) {
            field.setAccessible(true);
            Object value = field.get(msg);
            String fieldName = field.getName().toString();
            if(value!=null&&StringUtils.isNotBlank(value.toString())){
            	if(!"sign".equals(fieldName)&&!"signKey".equals(fieldName)
            			&&!"serialVersionUID".equals(fieldName)){
            		signMap.put(fieldName, value.toString());
            	}else if("signKey".equals(fieldName)){
            		signKey = value.toString();
            	}
            }
		}
		
		Collection<String> keyset= signMap.keySet();  
		List<String> list=new ArrayList<String>(keyset);  
		Collections.sort(list);
		
		StringBuilder sb = new StringBuilder();
		String key = null;
		for(int i=0;i<list.size();i++){
			key = list.get(i);
			sb.append(key+"="+signMap.get(key)+"&");
		}
		
		//加密原串+signKey
		String url = sb.substring(0, sb.length()-1) + signKey;
		System.out.println(url);
		String encodeStr = "";
		
		//SHA-256加密
		MessageDigest messageDigest;
		try {
            messageDigest = MessageDigest.getInstance("SHA-256");
            messageDigest.update(url.getBytes("UTF-8"));
            encodeStr = byte2Hex(messageDigest.digest());
        } catch (Exception e) {
            e.printStackTrace();
        }
		
        return encodeStr;
	}
	
	private String byte2Hex(byte[] bytes){
        StringBuffer stringBuffer = new StringBuffer();
        String temp = null;
        for (int i=0;i<bytes.length;i++){
            temp = Integer.toHexString(bytes[i] & 0xFF);
            if (temp.length()==1){
                //1得到一位的进行补0操作
                stringBuffer.append("0");
            }
            stringBuffer.append(temp);
        }
        return stringBuffer.toString();
    }
	
	public static void main(String[] args) throws Exception {
//		ApaySpdbCerHelper helper = new ApaySpdbCerHelper();
//		String json="{"
//    +"'txndir': 'A',"
//    +"'busicd': 'CANC',"
//    +" 'respcd': '00',"
//    +" 'inscd': '10130001',"
//    +" 'chcd': 'WXP',"
//    +" 'mchntid': '100000000000203',"
//    +" 'terminalid': 'gfb00001',"
//    +" 'channelOrderNum': '4200000028201712089810363093',"
//    +"  'consumerAccount': 'orS1BuPjp1KDg5iHnQZ4rVNyY6lg',"
//    +" 'errorDetail': '成功',"
//    +"  'orderNum': '2017120808287574',"
//    +" 'origOrderNum': 'SP17120808287573',"
//    +"  'sign': 'de1c036d7df5528dce133428b39afdc88cecc8268cc81861ada1ddd36a73f129',"
//    +" 'transTime': '2017-12-08 10:59:39'"
//+"}";
//		
//		ReverseBody body=helper.fromJson(json, ReverseBody.class);
//		body.setSignKey("zsdfyreuoyamdphhaweyrjbvzkgfdycs");
//		try {
//			helper.verify(body);
//		} catch (GopayException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
		ApaySpdbCerHelper helper = new ApaySpdbCerHelper();
	String transTime="2018-03-05T16:15:14 08:00";
	System.out.println(transTime.replaceAll(" ", "\\+"));
//	PayNotify response=new PayNotify();
//	
//	String sign = helper.getSign(response, PayNotify.class);
	String singStr="bankType=CFT&busicd=PAUT&channelOrderNum=4200000077201803053215972828&charset=utf-8&chcd=WXP&chcdDiscount=0.00&consumerAccount=ok3GRuCGKmbZoLn3Ckg8YYIkczb4&errorDetail=SUCCESS&inscd=93421888&mchntid=342642872780001&merDiscount=0.00&orderNum=SP18030508870577&payTime=2018-03-05 17:00:07&respcd=00&signType=SHA256&terminalid=gfb00001&transTime=2018-03-05T16:59:54+08:00&txamt=000000000001&txndir=A&version=2.27fac681eff04fae1905fab3fed44e91a";
	String encodeStr = "";
	
	//SHA-256加密
	MessageDigest messageDigest;
	try {
        messageDigest = MessageDigest.getInstance("SHA-256");
        messageDigest.update(singStr.getBytes("UTF-8"));
        encodeStr = helper.byte2Hex(messageDigest.digest());
        System.out.println("encodeStr==="+encodeStr);
    } catch (Exception e) {
        e.printStackTrace();
    }
	}
}
